package com.woniu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniu.exception.LXLGException;
import com.woniu.order.common.OrderResultCode;
import com.woniu.order.common.enums.OrderFlowingEnum;
import com.woniu.order.common.enums.OrderStatusEnum;
import com.woniu.order.infra.config.AlipayConfig;
import com.woniu.order.infra.model.Order;
import com.woniu.order.infra.mapper.OrderMapper;
import com.woniu.order.infra.model.OrderEntry;
import com.woniu.order.infra.model.OrderFlowing;
import com.woniu.order.infra.model.OrderLog;
import com.woniu.order.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.order.service.dto.CancelOrderDto;
import com.woniu.order.service.dto.OrderDto;
import com.woniu.order.service.param.DelCartServiceParam;
import com.woniu.order.service.param.OrderCreateServiceParam;
import com.woniu.order.service.param.OrderEntryServiceParam;
import com.woniu.order.service.param.SearchOrderServiceParam;
import com.woniu.product.client.CouponManageClient;
import com.woniu.product.client.CouponQueryClient;
import com.woniu.product.client.ProductManageClient;
import com.woniu.product.client.ProductQueryClient;
import com.woniu.product.client.param.AddCouponLogParram;
import com.woniu.product.client.param.DeductStockParam;
import com.woniu.product.client.param.UpdateCouponLogParam;
import com.woniu.product.client.result.CouponResultInfo;
import com.woniu.product.client.result.ReceiveRecordResultInfo;
import com.woniu.product.client.result.SkuResultInfo;
import com.woniu.result.Result;
import com.woniu.user.client.AddressQueryClient;
import com.woniu.user.client.UserInfoClient;
import com.woniu.user.client.UserVIPQueryClient;
import com.woniu.user.client.result.AddressResultInfo;
import com.woniu.user.client.result.UserResultInfo;
import com.woniu.user.client.result.UserVipRelationResultInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author Lucas
 * @since 2022-11-26
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Resource
    private UserInfoClient userInfoClient;

    @Resource
    private ProductQueryClient productQueryClient;

    @Resource
    private OrderEntryService orderEntryService;

    @Resource
    private AddressQueryClient addressQueryClient;

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Resource
    private CartService cartService;

    @Resource
    private OrderLogService orderLogService;

    @Resource
    private OrderFlowingService orderFlowingService;


    @Resource
    private ProductManageClient productManageClient;

    @Resource
    private CouponQueryClient couponQueryClient;

    @Resource
    private UserVIPQueryClient userVipQueryClient;

    @Resource
    private CouponManageClient couponManageClient;


    /**
     * 根据用户ID、订单状态查询订单
     *
     * @param searchOrderServiceParam
     * @return
     */
    @Override
    public List<OrderDto> searchOrder(SearchOrderServiceParam searchOrderServiceParam) {
        QueryWrapper<Order> qw = new QueryWrapper<>();
        qw.eq("user_id", searchOrderServiceParam.getUserId());
        if (searchOrderServiceParam.getOrderState() != null && searchOrderServiceParam.getOrderState() != "") {
            qw.eq("order_state", searchOrderServiceParam.getOrderState());
        }
        List<Order> orders = list(qw);
        List<OrderDto> orderDtos = BeanUtil.copyToList(orders, OrderDto.class);
        return orderDtos;
    }


    /**
     * 创建订单
     *
     * @param orderCreateServiceParam
     * @return
     */
    @Override
    @GlobalTransactional
    public OrderDto createOrder(OrderCreateServiceParam orderCreateServiceParam) throws Exception {
        //判断用户状态
        Result<UserResultInfo> userResultInfoResult = userInfoClient.searchUserInfo(orderCreateServiceParam.getUserId());
        log.info("用户信息：{}", userResultInfoResult);
        UserResultInfo userResultInfo = userResultInfoResult.getData();
        if (!userResultInfo.getUserState().equals("NORMAL")) {
            throw new LXLGException(OrderResultCode.USER_STATUS_ABNORMAL);
        }
        //查询商品信息，判断商品的库存、状态
        List<Integer> skuIds = orderCreateServiceParam.getOrderEntryParams().stream().map(i -> i.getSkuId()).collect(Collectors.toList());
        Result<List<SkuResultInfo>> listResult = productQueryClient.batchQuerySkus(skuIds);
        if (!listResult.isSuccess()) {
            throw new LXLGException(OrderResultCode.PRODUCT_QUERY_ABNORMAL);
        }
        Map<Integer, SkuResultInfo> skuResultInfoMap = listResult.getData().stream().collect(Collectors.toMap(r -> r.getSkuId(), r -> r));
        //计算商品总价
        BigDecimal totalAmount = new BigDecimal(0);
        for (OrderEntryServiceParam o : orderCreateServiceParam.getOrderEntryParams()) {
            SkuResultInfo skuResultInfo = skuResultInfoMap.get(o.getSkuId());
            if (!skuResultInfo.getSkuStatus().equals("ON_SALE")) {
                throw new LXLGException(OrderResultCode.PRODUCT_STATE_ABNORMAL);
            }
            if (skuResultInfo.getStock() < o.getQuantity()) {
                throw new LXLGException(OrderResultCode.PRODUCT_COUNT_UNDERSTOCK);
            }
            totalAmount = totalAmount.add(BigDecimal.valueOf(o.getQuantity()).multiply(skuResultInfo.getPrice()));
        }
        BigDecimal amount = totalAmount;
        //根据用户会员等级(打折)
        //用户信息
        Result<List<UserVipRelationResultInfo>> userVipCard = userVipQueryClient.getUserVipCard(orderCreateServiceParam.getUserId());
        List<UserVipRelationResultInfo> userVipCardData = userVipCard.getData();
        UserVipRelationResultInfo vipRelationResultInfo = userVipCardData.get(0);
        log.info("用户vip信息：{}", vipRelationResultInfo);
        //折扣
        BigDecimal discount = vipRelationResultInfo.getDiscount();
        log.info("折扣：{}", discount);
        //判断是否用券
        List<AddCouponLogParram> aclps = new ArrayList<>();
        if (!orderCreateServiceParam.getCouponReceiveIds().isEmpty()) {
            log.info("用券情况：{}", orderCreateServiceParam.getCouponReceiveIds());
            //用券情况（是否可以使用)
            List<CouponResultInfo> cs = new ArrayList<>();
            //获取订单商品可使用的优惠券
            for (Integer i : skuIds) {
                Result<List<CouponResultInfo>> listResult1 = couponQueryClient.searchCouponBySkuId(i);
                List<CouponResultInfo> couponResultInfos = listResult1.getData();
                cs.addAll(couponResultInfos);
            }
            log.info("订单商品可使用的优惠券：{}", cs);
            if (cs.isEmpty()) {
                throw new LXLGException(OrderResultCode.PRODUCT_CANT_USE_COUPON);
            }
            //获取可使用优惠券的ids
            List<Integer> integers = cs.stream().map(i -> i.getId()).collect(Collectors.toList());
            for (Integer c : orderCreateServiceParam.getCouponReceiveIds()) {
                //获取领取的优惠券信息
                Result<ReceiveRecordResultInfo> receiveRecordResultInfoResult = couponQueryClient.serachCuponByCouponReceiveId(c);
                ReceiveRecordResultInfo receiveRecordResultInfo = receiveRecordResultInfoResult.getData();
                if (receiveRecordResultInfo.getStatus().equals("USED")) {
                    throw new LXLGException(OrderResultCode.COUPON_HAS_BEEN_USED);
                }
                log.info("领取的优惠券信息：{}", receiveRecordResultInfo);
                //获取优惠券信息
                Result<CouponResultInfo> couponResultInfoResult = couponQueryClient.searchCouponByCouponId(receiveRecordResultInfo.getCouponId());
                CouponResultInfo couponResultInfo = couponResultInfoResult.getData();
                log.info("优惠券信息：{}", couponResultInfo);
                //判断用户是否拥有优惠券
                if (!receiveRecordResultInfo.getBuyerId().equals(orderCreateServiceParam.getUserId())) {
                    throw new LXLGException(OrderResultCode.COUPON_HAVE_NOT_OWNED);
                }
                //判断是否可叠加
                if (orderCreateServiceParam.getCouponReceiveIds().size() >= 2 && couponResultInfo.getType() != 2) {
                    throw new LXLGException(OrderResultCode.COUPON_CANT_ADD_UP);
                }
                //判断优惠券是否能在订单商品上使用
                if (!integers.contains(c)) {
                    throw new LXLGException(OrderResultCode.COUPON_NOT_APPLICABLE);
                }
                //判断是否达到满减金额
                if (receiveRecordResultInfo.getFullMoney().compareTo(amount) > 0) {
                    throw new LXLGException(OrderResultCode.COUPON_FAR_FROM_FULLMONEY);
                }
                BigDecimal couponMoney = receiveRecordResultInfo.getCouponMoney();
                amount = amount.subtract(couponMoney);
                //修改优惠券领取表状态
                couponManageClient.updateCouponReceive(c);
                //创建增加订单记录参数对象
                AddCouponLogParram addCouponLogParram = new AddCouponLogParram();
                addCouponLogParram.setBuyerId(orderCreateServiceParam.getUserId());
                addCouponLogParram.setCouponReceiveId(c);
                addCouponLogParram.setOrderOriginalAmount(totalAmount);
                addCouponLogParram.setCouponAmount(receiveRecordResultInfo.getCouponMoney());
                aclps.add(addCouponLogParram);
            }
        }
        BigDecimal orderPrice = amount.multiply(discount);
        //获取收货地址信息
        Result<List<AddressResultInfo>> listResult1 = addressQueryClient.getUserAddress(orderCreateServiceParam.getUserId(), orderCreateServiceParam.getAddressId());
        List<AddressResultInfo> addressResultInfos = listResult1.getData();
        log.info("用户地址信息：{}", addressResultInfos);
        if (addressResultInfos == null) {
            throw new LXLGException(OrderResultCode.ADDRESS_QUERY_ABNORMAL);
        }
        AddressResultInfo addressResultInfo = addressResultInfos.get(0);
        //生成订单
        Order order = new Order();
        order.setOrderNum(createOrderNum());
        order.setOrderUser(userResultInfo.getUserNickname());
        order.setUserId(orderCreateServiceParam.getUserId());
        order.setOrderAddress(addressResultInfo.getAddressInfo());
        order.setAddressId(orderCreateServiceParam.getAddressId());
        order.setReceiverUser(userResultInfo.getUserRealname());
        order.setReceiverPhone(addressResultInfo.getPhone());
        order.setOrderCreatetime(new Date());
        order.setOrderPrice(orderPrice);
        order.setOrderState(OrderStatusEnum.CREATED.getCode());
        save(order);
        //存入优惠券记录表
        if (!orderCreateServiceParam.getCouponReceiveIds().isEmpty()) {
            for (AddCouponLogParram addCouponLogParram : aclps) {
                addCouponLogParram.setOrderNumber(order.getOrderNum());
                addCouponLogParram.setOrderFinalAmount(orderPrice);
                couponManageClient.addCouponLog(addCouponLogParram);
            }
        }
        //存入订单商品信息
        for (OrderEntryServiceParam o : orderCreateServiceParam.getOrderEntryParams()) {
            OrderEntry orderEntry = new OrderEntry();
            orderEntry.setOrderId(order.getOrderId());
            orderEntry.setOrderNum(order.getOrderNum());
            orderEntry.setSkuId(o.getSkuId());
            SkuResultInfo skuResultInfo = skuResultInfoMap.get(o.getSkuId());
            orderEntry.setSkuName(skuResultInfo.getSkuCode());
            orderEntry.setQuantity(o.getQuantity());
            orderEntry.setPrice(skuResultInfo.getPrice());
            orderEntry.setSkuMainPic(skuResultInfo.getSkuMainPic());
            orderEntryService.save(orderEntry);
            //修改订单商品库存
            DeductStockParam deductStockParam = new DeductStockParam();
            deductStockParam.setProductId(o.getSkuId());
            deductStockParam.setQuantity(o.getQuantity());
            productManageClient.deductStock(deductStockParam);
        }
        //记录订单日志
        OrderLog orderLog = new OrderLog();
        orderLog.setUserId(order.getUserId());
        orderLog.setOrderId(order.getOrderId());
        orderLog.setOrderNum(order.getOrderNum());
        orderLog.setOrderContent("创建成功");
        orderLog.setLogTime(new Date());
        orderLogService.save(orderLog);
        //增减销量
        for (OrderEntryServiceParam o : orderCreateServiceParam.getOrderEntryParams()) {
            productManageClient.addSkuSalesCount(o.getSkuId(), o.getQuantity());
        }
        //发延迟消息确认订单状态(15s)
        CancelOrderDto cod = new CancelOrderDto();
        cod.setOrderId(order.getOrderId());
        cod.setOrderEntryServiceParams(orderCreateServiceParam.getOrderEntryParams());
        Message<CancelOrderDto> message = MessageBuilder.withPayload(cod).build();
        rocketMQTemplate.syncSend("lxlg-order-cancel", message, 2000, 6);
        return BeanUtil.copyProperties(order, OrderDto.class);
    }

    /**
     * 支付宝支付
     *
     * @param orderId
     * @return
     */
    @Override
    public String aliPay(Integer orderId) throws Exception {
        //查询订单
        Order order = getOne(new QueryWrapper<Order>().eq("order_id", orderId));
        log.info("订单：{}", order);
        if (order != null && order.getOrderState().equals(OrderStatusEnum.CREATED.getCode())) {
            //获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

            //设置请求参数
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
            alipayRequest.setReturnUrl(AlipayConfig.return_url);
            alipayRequest.setNotifyUrl(AlipayConfig.notify_url);


            //商户订单号，商户网站订单系统中唯一订单号，必填
            String out_trade_no = new String(order.getOrderNum().getBytes("ISO-8859-1"), "UTF-8");
            //付款金额，必填
            String total_amount = new String(order.getOrderPrice().toString().getBytes("ISO-8859-1"), "UTF-8");
            //订单名称，必填
            String subject = "支付商品";
            //商品描述，可空
            String body = "商品订单";

            alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                    + "\"total_amount\":\"" + total_amount + "\","
                    + "\"subject\":\"" + subject + "\","
                    + "\"body\":\"" + body + "\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

            //请求
            String result = alipayClient.pageExecute(alipayRequest).getBody();
            return result;
        }
        return null;
    }

    /**
     * 支付成功后业务处理
     *
     * @param orderId
     */
    @Override
    public void setPayOk(Integer orderId) {
        //修改订单状态
        Order order = getById(orderId);
        Integer userId = order.getUserId();
        order.setOrderState(OrderStatusEnum.PAID.getCode());
        order.setOrderPaytime(new Date());
        updateById(order);
        //清理购物车
        List<OrderEntry> orderEntries = orderEntryService.list(new QueryWrapper<OrderEntry>().eq("order_id", orderId));
        List<Integer> integers = orderEntries.stream().map(o -> o.getSkuId()).collect(Collectors.toList());
        for (Integer i : integers) {
            DelCartServiceParam delCartServiceParam = new DelCartServiceParam();
            delCartServiceParam.setSkuId(i);
            delCartServiceParam.setUserId(userId);
            cartService.delCart(delCartServiceParam);
        }
        //记录订单日志
        OrderLog ol = new OrderLog();
        ol.setUserId(userId);
        ol.setOrderId(orderId);
        ol.setOrderNum(order.getOrderNum());
        ol.setOrderContent("支付成功");
        ol.setLogTime(new Date());
        orderLogService.save(ol);
        //记录流水
        OrderFlowing of = new OrderFlowing();
        of.setOrderId(orderId);
        of.setFlowingType(OrderFlowingEnum.FLOWING_TYPE_OUT.getCode());
        of.setOrderPrice(order.getOrderPrice());
        of.setCreateTime(new Date());
        of.setAllowanceId(null);
        orderFlowingService.save(of);
        //优惠券信息更新
        UpdateCouponLogParam updateCouponLogParam = new UpdateCouponLogParam();
        updateCouponLogParam.setOrderNumber(order.getOrderNum());
        updateCouponLogParam.setBuyerId(userId);
        couponManageClient.updateCouponLog(updateCouponLogParam);
    }

    /**
     * 生成订单号
     *
     * @return
     */
    private String createOrderNum() {
        //workerId 机器ID  dataCenterId 机房ID
        return "LXLG" + IdUtil.getSnowflake(1, 1).nextIdStr();
    }


}
